#include "gtktreedatalist.h"
+static GMemChunk *tree_chunk = NULL;
+#define TREE_CHUNK_PREALLOCS 64
+
/* node allocation
*/
-struct _GAllocator /* from gmem.c */
-{
- gchar *name;
- guint16 n_preallocs;
- guint is_unused : 1;
- guint type : 4;
- GAllocator *last;
- GMemChunk *mem_chunk;
- GtkTreeDataList *free_nodes;
-};
-
-
-G_LOCK_DEFINE_STATIC (current_allocator);
-static GAllocator *current_allocator = NULL;
-
-/* HOLDS: current_allocator_lock */
-static void
-gtk_tree_data_list_validate_allocator (GAllocator *allocator)
-{
- g_return_if_fail (allocator != NULL);
- g_return_if_fail (allocator->is_unused == TRUE);
-
- if (allocator->type != G_ALLOCATOR_NODE)
- {
- allocator->type = G_ALLOCATOR_NODE;
- if (allocator->mem_chunk)
- {
- g_mem_chunk_destroy (allocator->mem_chunk);
- allocator->mem_chunk = NULL;
- }
- }
-
- if (!allocator->mem_chunk)
- {
- allocator->mem_chunk = g_mem_chunk_new (allocator->name,
- sizeof (GtkTreeDataList),
- sizeof (GtkTreeDataList) * allocator->n_preallocs,
- G_ALLOC_ONLY);
- allocator->free_nodes = NULL;
- }
-
- allocator->is_unused = FALSE;
-}
-
-void
-_gtk_tree_data_list_push_allocator (GAllocator *allocator)
-{
- G_LOCK (current_allocator);
- gtk_tree_data_list_validate_allocator ( allocator );
- allocator->last = current_allocator;
- current_allocator = allocator;
- G_UNLOCK (current_allocator);
-}
-
-void
-_gtk_tree_data_list_pop_allocator (void)
-{
- G_LOCK (current_allocator);
- if (current_allocator)
- {
- GAllocator *allocator;
-
- allocator = current_allocator;
- current_allocator = allocator->last;
- allocator->last = NULL;
- allocator->is_unused = TRUE;
- }
- G_UNLOCK (current_allocator);
-}
-
GtkTreeDataList *
_gtk_tree_data_list_alloc (void)
{
GtkTreeDataList *list;
- G_LOCK (current_allocator);
- if (!current_allocator)
- {
- GAllocator *allocator = g_allocator_new ("GTK+ default GtkTreeDataList allocator",
- 128);
- gtk_tree_data_list_validate_allocator (allocator);
- allocator->last = NULL;
- current_allocator = allocator;
- }
- if (!current_allocator->free_nodes)
- list = g_chunk_new (GtkTreeDataList, current_allocator->mem_chunk);
- else
- {
- list = current_allocator->free_nodes;
- current_allocator->free_nodes = list->next;
- }
- G_UNLOCK (current_allocator);
+ if (tree_chunk == NULL)
+ tree_chunk = g_mem_chunk_new ("treedatalist mem chunk",
+ sizeof (GtkTreeDataList),
+ sizeof (GtkTreeDataList) * TREE_CHUNK_PREALLOCS,
+ G_ALLOC_AND_FREE);
+
+ list = g_chunk_new (GtkTreeDataList, tree_chunk);
return list;
}
_gtk_tree_data_list_free (GtkTreeDataList *list,
GType *column_headers)
{
- GtkTreeDataList *tmp;
+ GtkTreeDataList *tmp, *next;
gint i = 0;
- for (tmp = list; tmp; tmp = tmp->next)
+ tmp = list;
+
+ while (tmp)
{
+ next = tmp->next;
if (g_type_is_a (column_headers [i], G_TYPE_STRING))
g_free ((gchar *) tmp->data.v_pointer);
else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT))
g_object_unref (G_OBJECT (tmp->data.v_pointer));
else if (g_type_is_a (column_headers [i], G_TYPE_BOXED))
g_boxed_free (column_headers [i], (gpointer) tmp->data.v_pointer);
+
+ g_mem_chunk_free (tree_chunk, tmp);
i++;
+ tmp = next;
}
-
- G_LOCK (current_allocator);
- list->next = current_allocator->free_nodes;
- current_allocator->free_nodes = list;
- G_UNLOCK (current_allocator);
}
gboolean
_gtk_tree_data_list_check_type (GType type)
{
gint i = 0;
-
static GType type_list[] =
{
G_TYPE_BOOLEAN,
G_TYPE_INVALID
};
+ if (! G_TYPE_IS_VALUE_TYPE (type))
+ return FALSE;
+
+
while (type_list[i] != G_TYPE_INVALID)
{
if (g_type_is_a (type, type_list[i]))
{
g_value_init (value, type);
- if (g_type_is_a (type, G_TYPE_BOOLEAN))
- g_value_set_boolean (value, (gboolean) list->data.v_int);
- else if (g_type_is_a (type, G_TYPE_CHAR))
- g_value_set_char (value, (gchar) list->data.v_char);
- else if (g_type_is_a (type, G_TYPE_UCHAR))
- g_value_set_uchar (value, (guchar) list->data.v_uchar);
- else if (g_type_is_a (type, G_TYPE_INT))
- g_value_set_int (value, (gint) list->data.v_int);
- else if (g_type_is_a (type, G_TYPE_UINT))
- g_value_set_uint (value, (guint) list->data.v_uint);
- else if (g_type_is_a (type, G_TYPE_ENUM))
- g_value_set_enum (value, list->data.v_int);
- else if (g_type_is_a (type, G_TYPE_FLAGS))
- g_value_set_flags (value, (int) list->data.v_int);
- else if (g_type_is_a (type, G_TYPE_FLOAT))
- g_value_set_float (value, (gfloat) list->data.v_float);
- else if (g_type_is_a (type, G_TYPE_DOUBLE))
- g_value_set_double (value, (gdouble) list->data.v_double);
- else if (g_type_is_a (type, G_TYPE_STRING))
- g_value_set_string (value, (gchar *) list->data.v_pointer);
- else if (g_type_is_a (type, G_TYPE_POINTER))
- g_value_set_pointer (value, (gpointer) list->data.v_pointer);
- else if (g_type_is_a (type, G_TYPE_BOXED))
- g_value_set_boxed (value, (gpointer) list->data.v_pointer);
- else if (g_type_is_a (type, G_TYPE_OBJECT))
- g_value_set_object (value, (GObject *) list->data.v_pointer);
- else
- g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
+ switch (G_TYPE_FUNDAMENTAL (type))
+ {
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (value, (gboolean) list->data.v_int);
+ break;
+ case G_TYPE_CHAR:
+ g_value_set_char (value, (gchar) list->data.v_char);
+ break;
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (value, (guchar) list->data.v_uchar);
+ break;
+ case G_TYPE_INT:
+ g_value_set_int (value, (gint) list->data.v_int);
+ break;
+ case G_TYPE_UINT:
+ g_value_set_uint (value, (guint) list->data.v_uint);
+ break;
+ case G_TYPE_ENUM:
+ g_value_set_enum (value, list->data.v_int);
+ break;
+ case G_TYPE_FLAGS:
+ g_value_set_flags (value, (int) list->data.v_int);
+ break;
+ case G_TYPE_FLOAT:
+ g_value_set_float (value, (gfloat) list->data.v_float);
+ break;
+ case G_TYPE_DOUBLE:
+ g_value_set_double (value, (gdouble) list->data.v_double);
+ break;
+ case G_TYPE_STRING:
+ g_value_set_string (value, (gchar *) list->data.v_pointer);
+ break;
+ case G_TYPE_POINTER:
+ g_value_set_pointer (value, (gpointer) list->data.v_pointer);
+ break;
+ case G_TYPE_BOXED:
+ g_value_set_boxed (value, (gpointer) list->data.v_pointer);
+ break;
+ case G_TYPE_OBJECT:
+ g_value_set_object (value, (GObject *) list->data.v_pointer);
+ break;
+ default:
+ g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
+ break;
+ }
}
void
_gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
GValue *value)
{
- if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_BOOLEAN))
- list->data.v_int = g_value_get_boolean (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_CHAR))
- list->data.v_char = g_value_get_char (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_UCHAR))
- list->data.v_uchar = g_value_get_uchar (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_INT))
- list->data.v_int = g_value_get_int (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ENUM))
- list->data.v_int = g_value_get_enum (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_FLAGS))
- list->data.v_int = g_value_get_flags (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_UINT))
- list->data.v_uint = g_value_get_uint (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_POINTER))
- list->data.v_pointer = g_value_get_pointer (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_FLOAT))
- list->data.v_float = g_value_get_float (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_DOUBLE))
- list->data.v_double = g_value_get_double (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_STRING))
- list->data.v_pointer = g_value_dup_string (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_OBJECT))
- list->data.v_pointer = g_value_dup_object (value);
- else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_BOXED))
- list->data.v_pointer = g_value_dup_boxed (value);
- else
- g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
+ switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
+ {
+ case G_TYPE_BOOLEAN:
+ list->data.v_int = g_value_get_boolean (value);
+ break;
+ case G_TYPE_CHAR:
+ list->data.v_char = g_value_get_char (value);
+ break;
+ case G_TYPE_UCHAR:
+ list->data.v_uchar = g_value_get_uchar (value);
+ break;
+ case G_TYPE_INT:
+ list->data.v_int = g_value_get_int (value);
+ break;
+ case G_TYPE_ENUM:
+ list->data.v_int = g_value_get_enum (value);
+ break;
+ case G_TYPE_FLAGS:
+ list->data.v_int = g_value_get_flags (value);
+ break;
+ case G_TYPE_UINT:
+ list->data.v_uint = g_value_get_uint (value);
+ break;
+ case G_TYPE_POINTER:
+ list->data.v_pointer = g_value_get_pointer (value);
+ break;
+ case G_TYPE_FLOAT:
+ list->data.v_float = g_value_get_float (value);
+ break;
+ case G_TYPE_DOUBLE:
+ list->data.v_double = g_value_get_double (value);
+ break;
+ case G_TYPE_STRING:
+ list->data.v_pointer = g_value_dup_string (value);
+ break;
+ case G_TYPE_OBJECT:
+ list->data.v_pointer = g_value_dup_object (value);
+ break;
+ case G_TYPE_BOXED:
+ list->data.v_pointer = g_value_dup_boxed (value);
+ break;
+ default:
+ g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
+ break;
+ }
}
-GtkTreeDataList*
+GtkTreeDataList *
_gtk_tree_data_list_node_copy (GtkTreeDataList *list,
GType type)
{
new_list = _gtk_tree_data_list_alloc ();
new_list->next = NULL;
-
- if ((g_type_is_a (type, G_TYPE_UINT)) ||
- (g_type_is_a (type, G_TYPE_INT)) ||
- (g_type_is_a (type, G_TYPE_UCHAR)) ||
- (g_type_is_a (type, G_TYPE_CHAR)) ||
- (g_type_is_a (type, G_TYPE_BOOLEAN)) ||
- (g_type_is_a (type, G_TYPE_POINTER)) ||
- (g_type_is_a (type, G_TYPE_FLOAT)) ||
- (g_type_is_a (type, G_TYPE_DOUBLE)))
- new_list->data = list->data;
- else if (g_type_is_a (type, G_TYPE_STRING))
- new_list->data.v_pointer = g_strdup (list->data.v_pointer);
- else if (g_type_is_a (type, G_TYPE_OBJECT))
+ switch (G_TYPE_FUNDAMENTAL (type))
{
+ case G_TYPE_UINT:
+ case G_TYPE_INT:
+ case G_TYPE_UCHAR:
+ case G_TYPE_CHAR:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_POINTER:
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ new_list->data = list->data;
+ break;
+ case G_TYPE_STRING:
+ new_list->data.v_pointer = g_strdup (list->data.v_pointer);
+ break;
+ case G_TYPE_OBJECT:
new_list->data.v_pointer = list->data.v_pointer;
if (new_list->data.v_pointer)
g_object_ref (G_OBJECT (new_list->data.v_pointer));
- }
- else if (g_type_is_a (type, G_TYPE_BOXED))
- {
+ break;
+ case G_TYPE_BOXED:
if (list->data.v_pointer)
new_list->data.v_pointer = g_boxed_copy (type, list->data.v_pointer);
else
new_list->data.v_pointer = NULL;
+ break;
+ default:
+ g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
+ break;
}
- else
- g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
return new_list;
}
-
-
last_column &&
!(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
- last_column = last_column->prev)
- ;
+ last_column = last_column->prev);
for (first_column = tree_view->priv->columns;
first_column &&
!(GTK_TREE_VIEW_COLUMN (first_column->data)->visible) &&
GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button);
- first_column = first_column->next)
- ;
+ first_column = first_column->next);
- /* no headers are visible, or are focussable. We can't focus in or out.
- * I wonder if focussable is a real word...
+ /* No headers are visible, or are focusable. We can't focus in or out.
*/
if (last_column == NULL)
return FALSE;
- /* First thing we want to handle is entering and leaving the headers.
- */
switch (dir)
{
case GTK_DIR_TAB_BACKWARD:
- if (!focus_child)
- {
- focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
- gtk_widget_grab_focus (focus_child);
- goto cleanup;
- }
- if (focus_child == GTK_TREE_VIEW_COLUMN (first_column->data)->button)
- {
- focus_child = NULL;
- goto cleanup;
- }
- break;
-
case GTK_DIR_TAB_FORWARD:
- if (!focus_child)
+ case GTK_DIR_UP:
+ case GTK_DIR_DOWN:
+ if (focus_child == NULL)
{
- focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
+ if (tree_view->priv->focus_column == NULL)
+ focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
+ else
+ focus_child = GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data)->button;
gtk_widget_grab_focus (focus_child);
- goto cleanup;
+ break;
}
- if (focus_child == GTK_TREE_VIEW_COLUMN (last_column->data)->button)
- {
- focus_child = NULL;
- goto cleanup;
- }
- break;
+ return FALSE;
case GTK_DIR_LEFT:
- if (!focus_child)
- {
- focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
- gtk_widget_grab_focus (focus_child);
- goto cleanup;
- }
- if (focus_child == GTK_TREE_VIEW_COLUMN (first_column->data)->button)
- {
- focus_child = NULL;
- goto cleanup;
- }
- break;
-
case GTK_DIR_RIGHT:
- if (!focus_child)
+ if (focus_child == NULL)
{
- focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
- gtk_widget_grab_focus (focus_child);
- goto cleanup;
+ g_assert_not_reached ();
+ return FALSE;
}
- if (focus_child == GTK_TREE_VIEW_COLUMN (last_column->data)->button)
+
+ if (gtk_container_focus (GTK_CONTAINER (focus_child), dir))
{
- focus_child = NULL;
- goto cleanup;
+ /* The focus moves inside the button. */
+ /* This is probably a great example of bad UI */
+ break;
}
- break;
- case GTK_DIR_UP:
- if (!focus_child)
+ /* We need to move the focus among the row of buttons. */
+ for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
+ if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
+ break;
+
+ if (tmp_list == first_column && dir == GTK_DIR_LEFT)
{
- focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
+ focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
gtk_widget_grab_focus (focus_child);
+ break;
}
- else
- {
- focus_child = NULL;
- }
- goto cleanup;
-
- case GTK_DIR_DOWN:
- if (!focus_child)
+ else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
{
focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
gtk_widget_grab_focus (focus_child);
+ break;
}
- else
- {
- focus_child = NULL;
- }
- goto cleanup;
- }
- /* We need to move the focus to the next button. */
- if (focus_child)
- {
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
- {
- if (gtk_container_focus (GTK_CONTAINER (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button), dir))
- {
- /* The focus moves inside the button. */
- /* This is probably a great example of bad UI */
- goto cleanup;
- }
- break;
- }
-
- /* We need to move the focus among the row of buttons. */
while (tmp_list)
{
GtkTreeViewColumn *column;
- if (dir == GTK_DIR_RIGHT || dir == GTK_DIR_TAB_FORWARD)
+ if (dir == GTK_DIR_RIGHT)
tmp_list = tmp_list->next;
else
tmp_list = tmp_list->prev;
if (tmp_list == NULL)
{
g_warning ("Internal button not found");
- goto cleanup;
+ break;
}
column = tmp_list->data;
if (column->button &&
break;
}
}
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
}
- cleanup:
/* if focus child is non-null, we assume it's been set to the current focus child
*/
if (focus_child)
switch (direction)
{
case GTK_DIR_LEFT:
+ case GTK_DIR_RIGHT:
return (gtk_tree_view_header_focus (tree_view, direction));
case GTK_DIR_TAB_BACKWARD:
case GTK_DIR_UP:
return FALSE;
case GTK_DIR_TAB_FORWARD:
- if (gtk_tree_view_header_focus (tree_view, direction))
- return TRUE;
- case GTK_DIR_RIGHT:
case GTK_DIR_DOWN:
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
gtk_widget_grab_focus (GTK_WIDGET (container));
_gtk_tree_view_column_unset_tree_view (column);
+ if (GTK_TREE_VIEW_COLUMN (tree_view->priv->focus_column->data) == column)
+ tree_view->priv->focus_column = NULL;
+
tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
g_object_unref (G_OBJECT (column));